package com.zqweb.gulimall.order.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;

@Configuration
public class RabbitMQConfig {
    // RabbitMQ的配置类
    // 只需声明，无需使用@Autowired自动引入，因为这里就是要代理rabbitTemplate增加新功能，否则会报循环依赖异常！
    private RabbitTemplate rabbitTemplate;

    @Primary
    @Bean
    // 通过连接工厂，创建RabbitTemplate，再调用序列化方法和加入确认回调机制方法，再来重新注入到容器中
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setMessageConverter(customMsgSerializer());
        initRabbitTemplate();
        return rabbitTemplate;
    }

    // 自定义消息的序列化机制（发送与存储）
    @Bean
    public MessageConverter customMsgSerializer(){
        return new Jackson2JsonMessageConverter();
    }

    // 在RabbitMQConfig配置类成功创建后，初始化RabbitTemplate组件，加入消息的确认回调
    // @PostConstruct
    public void initRabbitTemplate(){
        // 1、加入消息成功发送到Broker后的confirmCallback
        this.rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            /**
             * correlation：当前消息的唯一标识（用唯一id构建）
             * ack：消息是否成功发给Broker
             * reason：未成功的原因
             */
            public void confirm(CorrelationData correlationData, boolean ack, String reason) {
                System.out.println("correlationData = " + correlationData);
                System.out.println("ack = " + ack);
                System.out.println("reason = " + reason);
            }
        });
        // 2、加入消息未成功投递给指定Queue后的returnCallback
        this.rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            /**
             * message：投递失败的详细信息
             * replyCode：回复的状态码（如：312，表示RoutingKey有问题，找不到要投递的队列）
             * replyText：回复的文本内容
             * exchange：消息是由哪个交换机开始投递的
             * routingKey：投递时使用的路由键
             */
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                System.out.println("message = " + message);
                System.out.println("replyCode = " + replyCode + ",replyText = " + replyText);
                System.out.println("exchange = " + exchange + ",routingKey = " + routingKey);
            }
        });

    }

}
